Jerry's Log

Mono & Flux

contents

Spring WebFlux(리액티브 프로그래밍)의 핵심입니다. 기존 Spring MVC(Blocking)에서 WebFlux(Non-blocking)로 넘어가려면 MonoFlux를 이해하는 것은 필수입니다.

이 둘은 리액티브 스트림 표준(Project Reactor)에서 Publisher(발행자) 인터페이스를 구현한 두 가지 주요 타입입니다.

상세 내용은 다음과 같습니다.


1. 패러다임의 전환: Pull vs. Push

2. Mono란 무엇인가? (0 또는 1)

Mono<T>최대 1개의 데이터를 발행하는 Publisher입니다.

코드 예시:

// 여기선 아무 일도 안 일어납니다! 그냥 정의일 뿐입니다.
Mono mono = Mono.just("Hello World");

// 구독(subscribe)을 해야만 데이터가 흐릅니다.
mono.subscribe(System.out::println); 

3. Flux란 무엇인가? (0 ~ N)

Flux<T>0개에서 무한대의 데이터를 발행하는 Publisher입니다.

코드 예시:

// 3개의 아이템이 흐르는 스트림
Flux flux = Flux.just("Apple", "Banana", "Cherry");

flux.subscribe(item -> System.out.println("Received: " + item));

4. 결정적 개념: "구독하기 전까진 아무 일도 없다"

초보자가 가장 헷갈려 하는 부분입니다. 일반 자바에서는:

List list = repository.findAll(); // 여기서 즉시 DB 호출이 발생합니다.

Reactor/WebFlux에서는:

Flux users = repository.findAll(); // 아무 일도 안 일어납니다. DB 호출 안 함.

Flux는 그저 요리법(Recipe) 이자 설계도일 뿐입니다. 실제 실행(DB 쿼리, HTTP 호출)은 누군가가 .subscribe()를 호출할 때 비로소 시작됩니다. Spring WebFlux 컨트롤러에서는 요청이 들어올 때 웹 프레임워크(Netty) 가 알아서 구독을 해줍니다.


5. 주요 연산자 (도구 상자)

자바 스트림처럼 연산자를 사용해 데이터를 가공합니다.

A. map (동기적 변환)

데이터를 1:1로 동기적으로 변환할 때 씁니다.

flux.map(user -> new UserDto(user.getName()));

B. flatMap (비동기적 변환)

변환 작업이 또 다른 비동기 호출(DB나 API 호출 등)을 포함할 때 씁니다.

// 각 유저에 대해 외부 API를 호출해 상세 정보를 가져옴
flux.flatMap(user -> externalService.getDetails(user.getId()));

C. zip (결합)

여러 비동기 작업을 병렬(Parallel) 로 실행하고 그 결과를 합칠 때 씁니다.

Mono userMono = repo.findUser();
Mono ordersMono = repo.findOrders();

// 둘 다 병렬로 실행하고, 둘 다 끝날 때까지 기다렸다가 합침
Mono.zip(userMono, ordersMono)
    .map(tuple -> new Dashboard(tuple.getT1(), tuple.getT2()));

6. 백프레셔 (Backpressure - 안전 밸브)

이것이 Flux의 초능력입니다.

빠른 생산자(서버)가 초당 10,000개를 보내는데, 느린 소비자(클라이언트)가 초당 100개밖에 처리 못 한다고 가정해 봅시다.


요약 테이블

특징 Mono Flux
개수 (Cardinality) 0 또는 1개 0 ~ N개 (무한 가능)
Java 대응 CompletableFuture, Optional List, Stream
에러 처리 에러와 함께 종료 에러와 함께 종료
백프레셔 해당 없음 (1개뿐이라) 매우 중요
주요 용도 findById, save, HTTP 응답 findAll, 데이터 스트림, SSE

references